﻿using System;
using System.Data;
using System.Data.Common;

namespace Sofire.Data
{
    public partial class QueryEngineBase
    {
        internal ScalarResult ExecuteScalar(DbConnection connection, ExecuteCommand command, bool autoClosed)
        {
            object result = null;
            Exception exception = null;
            DbCommand dbCommand = this.CreateCommand(connection, command);

            command.Aborted = false;
            var userToken = this.OnExecuting(ExecuteType.Scalar, command);
            try
            {
                if(connection.State == ConnectionState.Closed)
                    connection.Open();
                result = dbCommand.ExecuteScalar();
                if(Convert.IsDBNull(result)) result = null;
            }
            catch(Exception ex)
            {
                if(command.Aborted)
                {
                    exception = ExecuteAbortException.Instance;
                }
                else
                {
                    exception = ex;
                }
            }
            finally
            {
                if(autoClosed) connection.TryClose();
            }
            var r = new ScalarResult();
            r.Initialization(this, dbCommand, result, exception);

            this.OnExecuted(ExecuteType.Scalar, r, command, userToken);

            return r;
        }

        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="command">执行查询的命令。</param>
        public ScalarResult ExecuteScalar(ExecuteCommand command)
        {
            return this.ExecuteScalar(this.CreateConnection(), command, true);
        }

        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        public ScalarResult ExecuteScalar(string commandText)
        {
            return this.ExecuteScalar(new ExecuteCommand(commandText));
        }

        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ScalarResult ExecuteScalar(string commandText, ExecuteParameterCollection parameters)
        {
            return this.ExecuteScalar(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">匹配 Name/Value 的参数集合或 数组。</param>
        public ScalarResult ExecuteScalar(string commandText, params object[] parameters)
        {
            return this.ExecuteScalar(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ScalarResult ExecuteScalar(string commandText, params ExecuteParameter[] parameters)
        {
            return this.ExecuteScalar(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="objectInstance">任意类型的实例。</param>
        public ScalarResult ExecuteScalar(string commandText, object objectInstance)
        {
            return this.ExecuteScalar(new ExecuteCommand(commandText, new ExecuteParameterCollection(objectInstance)));
        }
    }

    public partial class QueryContext
    {
        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="command">执行查询的命令。</param>
        public ScalarResult ExecuteScalar(ExecuteCommand command)
        {
            return this.Engine.ExecuteScalar(this.Connection, command, false);
        }

        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        public ScalarResult ExecuteScalar(string commandText)
        {
            return this.ExecuteScalar(new ExecuteCommand(commandText));
        }

        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ScalarResult ExecuteScalar(string commandText, ExecuteParameterCollection parameters)
        {
            return this.ExecuteScalar(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">匹配 Name/Value 的参数集合或 数组。</param>
        public ScalarResult ExecuteScalar(string commandText, params object[] parameters)
        {
            return this.ExecuteScalar(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="parameters">参数集合。</param>
        public ScalarResult ExecuteScalar(string commandText, params ExecuteParameter[] parameters)
        {
            return this.ExecuteScalar(new ExecuteCommand(commandText, parameters));
        }

        /// <summary>
        /// 执行查询，并返回查询结果集中第一行的第一列。忽略额外的列或行。
        /// </summary>
        /// <param name="commandText">Transact-SQL 语句。第一个字符为“>”时，表示一个存储过程。</param>
        /// <param name="objectInstance">任意类型的实例。</param>
        public ScalarResult ExecuteScalar(string commandText, object objectInstance)
        {
            return this.ExecuteScalar(new ExecuteCommand(commandText, new ExecuteParameterCollection(objectInstance)));
        }
    }
}